package com.cfh.springcloudclientapplication.loadbalance;

import com.sun.net.httpserver.Headers;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.stream.Collectors;

public class LoadBalancedClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {

    @Autowired
    private DiscoveryClient discoveryClient;

    private volatile Map<String, Set<String>> targetUrlsCache = new HashMap<>();

    @Scheduled(fixedRate = 10 * 1000)
    public void updateServiceNames() {
        Map<String, Set<String>> newTargetUrlsCache = this.targetUrlsCache;
        discoveryClient.getServices().forEach(serviceName -> {
            List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
            Set<String> newTargetUrls = instances
                    .stream()
                    .map(s ->
                            s.isSecure() ?
                                    "https://" + s.getHost() + ":" + s.getPort() :
                                    "http://" + s.getHost() + ":" + s.getPort()
                    )
                    .collect(Collectors.toSet());
            newTargetUrlsCache.put(serviceName, newTargetUrls);
        });
        this.targetUrlsCache = newTargetUrlsCache;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        URI requestURI = request.getURI();
        String path = requestURI.getPath();
        String[] strings = StringUtils.split(path, "/");
        String serviveName = strings[0];
        String uri = strings[1];
        //服务器列表
        List<String> targetUrls = new ArrayList<>(targetUrlsCache.get(serviveName));
        //选择
        int index = new Random().nextInt(targetUrls.size());
        String targetUrl = targetUrls.get(index);
        String actualUrl = targetUrl + "/" + uri + "?" + requestURI.getQuery();
        URL url = new URL(actualUrl);

        System.out.println("本次请求url:" + actualUrl);
        URLConnection urlConnection = url.openConnection();
        InputStream inputStream = urlConnection.getInputStream();
        HttpHeaders httpHeaders = new HttpHeaders();


        return new SimpleClientHttpResponse(inputStream, httpHeaders);
    }


    private static class SimpleClientHttpResponse implements ClientHttpResponse {

        private InputStream inputStream;

        private HttpHeaders httpHeaders;

        public SimpleClientHttpResponse(InputStream inputStream, HttpHeaders httpHeaders) {
            this.inputStream = inputStream;
            this.httpHeaders = httpHeaders;
        }

        @Override
        public HttpStatus getStatusCode() throws IOException {
            return HttpStatus.OK;
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return 200;
        }

        @Override
        public String getStatusText() throws IOException {
            return "OK";
        }

        @Override
        public void close() {

        }

        @Override
        public InputStream getBody() throws IOException {
            return inputStream;
        }

        @Override
        public HttpHeaders getHeaders() {
            return httpHeaders;
        }
    }
}
